﻿namespace ScrumLite.Services
{
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Transactions;
    using System.Linq;
    using Contracts;
    using System.Globalization;

    public class LinqDefectsService : IDefectsService
    {

        ScrumLite.Data.IDefectStore store;

        public LinqDefectsService(ScrumLite.Data.IDefectStore store)
        {
            this.store = store;
        }

        public LinqDefectsService()
            : this(new ScrumLite.Data.DefectStore())
        {
        }

        public Collection<Defect> GetDefects(string projectId, byte triaged)
        {

            List<Defect> defects = new List<ScrumLite.Data.Defect>(
                    this.store.RetrieveDefects(new Guid(projectId), (triaged==1?true:false))).
                ConvertAll<Defect>(delegate(ScrumLite.Data.Defect def)
                {
                    return new Defect()
                    {
                        Id = def.id,
                        Decision = def.decision,
                        CreatedOn = def.createdOn,
                        Moniker = def.moniker,
                        Notes = def.notes,
                        Severity = (int)def.severity,
                        Title = def.title,
                        Triaged = def.triagedOn.HasValue,
                        TriagedOn = def.triagedOn,
                        CreatedBy = def.user_createdBy,
                        DaysOpen = (def.triagedOn != null) ? ((TimeSpan)(def.triagedOn - def.createdOn)).Days : ((TimeSpan)(DateTime.Today - def.createdOn)).Days,
                        DeliverableId = def.fk_deliverable
                    };
                });

            return new Collection<Defect>(defects);

        }

        public Defect GetDefect(string projectId, int moniker)
        {
            ScrumLite.Data.Defect def = this.store.RetrieveDefect(projectId, moniker);

            Defect d = new Defect()
            {
                Id = def.id,
                Decision = def.decision,
                CreatedOn = def.createdOn,
                Moniker = def.moniker,
                Notes = def.notes,
                Severity = (int)def.severity,
                Title = def.title,
                Triaged = def.triagedOn.HasValue,
                TriagedOn = def.triagedOn,
                CreatedBy = def.user_createdBy,
                DeliverableId = def.fk_deliverable
            };

            return d;
        }

        public void AddDefect(Defect defect)
        {
            using (TransactionScope scope = new TransactionScope())
            {
                ScrumLite.Data.Defect d = new ScrumLite.Data.Defect()
                {
                    id = defect.Id,
                    decision = defect.Decision,
                    createdOn = defect.CreatedOn,
                    moniker = defect.Moniker,
                    notes = defect.Notes,
                    severity = (byte?)defect.Severity,
                    title = defect.Title,
                    triagedOn = defect.TriagedOn,
                    user_createdBy = defect.CreatedBy,
                    fk_deliverable = defect.DeliverableId
                };
                this.store.Add(d);
                scope.Complete();
            }
        }

        public void UpdateDefect(Defect defect)
        {

            using (TransactionScope scope = new TransactionScope())
            {
                ScrumLite.Data.Defect d = new ScrumLite.Data.Defect()
                {
                    id = defect.Id,
                    decision = defect.Decision,
                    createdOn = defect.CreatedOn,
                    moniker = defect.Moniker,
                    notes = defect.Notes,
                    severity = (byte?)defect.Severity,
                    title = defect.Title,
                    triagedOn = defect.TriagedOn,
                    user_createdBy = defect.CreatedBy,
                    fk_deliverable = defect.DeliverableId

                };
                this.store.Update(d);
                scope.Complete();
            }
        }

        public int GetNextMoniker(string projectId)
        {
            int maxMoniker = this.store.RetrieveLastMoniker(new Guid(projectId));
            return ++maxMoniker;
        }

        public void DeleteDefect(Guid defectId)
        {
            using (TransactionScope scope = new TransactionScope())
            {
                this.store.Delete(defectId);
                scope.Complete();
            }
        }

        public void SaveDefects(Defect[] defects)
        {
            using (TransactionScope scope = new TransactionScope())
            {
                foreach (Defect defect in defects)
                {
                    ScrumLite.Data.Defect d = new ScrumLite.Data.Defect()
                    {
                        id = defect.Id,
                        decision = defect.Decision,
                        createdOn = defect.CreatedOn,
                        moniker = defect.Moniker,
                        notes = defect.Notes,
                        severity = (byte?)defect.Severity,
                        title = defect.Title,
                        user_createdBy = defect.CreatedBy,
                        fk_deliverable = defect.DeliverableId
                    };
                    if (defect.Triaged && !defect.TriagedOn.HasValue)
                    {
                        d.triagedOn = DateTime.Now;
                    }
                    else
                    {
                        d.triagedOn = defect.TriagedOn;
                    }
                    this.store.Update(d);
                }
                scope.Complete();
            }
        }

        public Defect[] GetDefectsByDeliverable(string projectId, string deliverableId)
        {
            List<Defect> defects = new List<ScrumLite.Data.Defect>(
                               this.store.RetrieveDefects(new Guid(projectId), true)).
                           ConvertAll<Defect>(delegate(ScrumLite.Data.Defect def)
                           {
                               return new Defect()
                               {
                                   Id = def.id,
                                   Decision = def.decision,
                                   CreatedOn = def.createdOn,
                                   Moniker = def.moniker,
                                   Notes = def.notes,
                                   Severity = (int)def.severity,
                                   Title = def.title,
                                   Triaged = def.triagedOn.HasValue,
                                   TriagedOn = def.triagedOn,
                                   CreatedBy = def.user_createdBy,
                                   DaysOpen = (def.triagedOn != null) ? ((TimeSpan)(def.triagedOn - def.createdOn)).Days : ((TimeSpan)(DateTime.Today - def.createdOn)).Days,
                                   DeliverableId = def.fk_deliverable
                               };
                           });

            return defects.Where(d => d.DeliverableId.ToString().ToLower(CultureInfo.InvariantCulture).Equals(deliverableId.ToLower(CultureInfo.InvariantCulture))).ToArray();            
        }


    }
}
